const fontSize = 10;
const symbolSize = 40;
const padding = 10;

/*
* 调用 new Togo(svg,option).render();
* */
class Togo {
    /**/
    constructor(svg, option) {
        this.data = option.data;
        this.edges = option.edges;
        this._data = [];
        let group = [];

        // this.group = option.group;
        this.svg = d3.select(svg);

        let copyData = JSON.parse(JSON.stringify(this.data))

        let _groups_childs_group = []

        copyData.forEach((ass, i) => {
            if (ass.children && ass.children.length > 0) {

                if (ass.type == 'IBGP') {
                    _groups_childs_group.push(ass);
                    group.push(ass)
                } else {
                    ass._children = [];
                    ass.children.forEach((groups) => {
                        group.push(groups)
                        if (groups.children && groups.children.length > 0) {
                            groups.children.forEach((groupChild) => {
                                ass._children.push(groupChild)
                            })
                        }
                        // _groups_childs_group.push(groups) ;
                    })
                    //  ass.children = null;
                    //   ass.children = ass._children

                    let ass_obj = { children: ass._children, type: ass.type }
                    ass.children.push(ass_obj);
                    group.push(ass);
                    _groups_childs_group.push(ass);
                }
            }
        })

        console.log(_groups_childs_group);
        console.log(group);

        //  this._groups = group;
        this._groups = _groups_childs_group

    }

    //主渲染方法
    render() {
        this.scale = 1;
        this.width = this.svg.attr('width');
        this.height = this.svg.attr('height');
        this.container = this.svg.append('g')
            .attr('transform', 'scale(' + this.scale + ')');


        this.initNodeGroupPosition();
        this.initPosition();


        this.initDefineSymbol();
        this.initLink();
        this.initNode();

        this.initZoom();

        let _this = this;

        this.simulation.on("tick", () => {
           
            _this.group_nodes.attr('transform',
                d => {

                    return "translate(" + d.x + "," + d.y + ")"

                })



            _this.areaGroup.attr('transform', m =>
                "translate(" + m.x + "," + m.y + ")")

            _this.group_nodes_circle
                .attr("cx", d => {
                    _this.updateGroupPosition(d)
                    _this.update(d)
                    return d.x
                })
                .attr("cy", d => {
                    //  _this.update()
                    return d.y
                });


            _this.nodes.attr('transform',
                d => {
                    return "translate(" + d.x + "," + d.y + ")"

                })

            _this.arrea_nodes.attr('transform',
                d => {
                    return "translate(" + d.x + "," + d.y + ")"

                })

            // _this.update()

        })


    }

    //初始化节点位置
    initPosition() {
        let _this = this;
        let n = this.data.length;

        let _data = [];
        let _groups_update = []

        _this.data.forEach((group, index) => {

            if (group['children'] && group['children'].length > 0) {
                let _origin = [group.x, group.y]
                let n = group.children.length;
                let pointItem = _this.getVertices(_origin, Math.min(_this.width / n * (index + 1), _this.height / n * (index + 1)) * 0.3, n);

                if (group.type == 'OSPF') {
                    let outterItem = [];  //相交外圈节点
                    let innerItem = []; //骨干区域节点集合
                    let outterGroup = [];  //与骨干相交的组
                    let idx_inner = []; //骨干区域id
                    let gg_nodes = [];
                    group.children.forEach((child, iGroup) => {
                        if (child.children && child.children.length > 0) {
                            if (child.type !== 'GG') {
                                outterGroup.push(child);
                                child.children.forEach((mainItem, mainIndex) => {
                                    outterItem.push(mainItem)
                                })
                            } else {
                                child.children.forEach((mainItem, mainIndex) => {
                                    innerItem.push(mainItem)
                                    idx_inner.push(mainItem.id)
                                })
                            }
                        } else {
                            outterItem.push(child)
                        }
                    })

                    if (outterGroup.length > 0) {


                        //外圈zu
                        //当内圈有多个相交时
                        let _innerItem = [];//内圈全部node

                        let iInner = []  //内外圈交集id集合

                        let commomOutterItem = []; //内圈与外圈交集\

                        outterGroup.forEach((groups, i) => {
                            //group内外圆圈的交集
                            groups.children.forEach(function (v) {
                                if (idx_inner.indexOf(v.id) !== -1) {
                                    _innerItem.push(v)
                                    iInner.push(v.id)
                                    commomOutterItem.push(v)
                                }
                            })

                        })


                        //内圈的差集  --非相交部分
                        // let arr_inner = _innerItem.concat(innerItem);
                        innerItem.forEach(function (v) {
                            let a = idx_inner.indexOf(v.id) === -1 || (iInner.indexOf(v.id) === -1)
                            if (a) {
                                _innerItem.push(v)
                            }

                        })

                        innerItem = null;
                        innerItem = _innerItem //确保内圈有多个交集时，顺序排序

                        //内圈坐标
                        let n_inner = innerItem.length;
                        let r_inner = 30 * n_inner;
                        let thta = 360 / n_inner;

                        let pointItem_inner = _this.getVertices(_origin, r_inner, n_inner);
                        innerItem.forEach((item, i) => {
                            item.x = pointItem_inner[i].x
                            item.y = pointItem_inner[i].y
                            item['ox'] = group.x;
                            item['oy'] = group.y;
                            _data.push(item)

                            _groups_update.push(item)
                            gg_nodes.push(item)

                        })


                        //外圈与内圈不相交部分

                        let differItem_allOutter = outterItem.filter(function (v) {
                            return idx_inner.indexOf(v.id) === -1
                        })

                        let n_differ = differItem_allOutter.length; // 外圈差集长度
                        let r_outter = 60 * n_differ; //外圈半径


                        group['outterGroup'] = outterGroup
                        //外圈组
                        outterGroup.forEach((groups, i) => {
                            //group内外圆圈的交集

                            //交集id
                            let conId = []
                            let commomItem = groups.children.filter(function (v) {
                                if (idx_inner.indexOf(v.id) !== -1) {
                                    conId.push(v.id)
                                }
                            })

                            let points = [];//内外圆交集的坐标
                            innerItem.forEach((item) => {
                                conId.forEach((id) => {
                                    if (item.id == id) {
                                        let arr = []
                                        arr[0] = item.x
                                        arr[1] = item.y
                                        points.push(arr)
                                    }
                                })

                            })

                            let points_thta = []
                            points.forEach((point) => {
                                let a = _this.getAngle1(point[0], point[1], _origin[0], _origin[1])
                                point.thta = a; //内外圆坐标的角度
                                points_thta.push(a);
                            })

                            let points_thta_max = d3.max(points_thta)

                            //外圈的差集
                            let arr3 = commomItem.concat(groups.children);
                            let differItem = arr3.filter(function (v) {
                                return idx_inner.indexOf(v.id) === -1 || (conId.indexOf(v.id) === -1)
                            })

                            let thta_outter = (thta * points_thta.length) / (differItem.length + 1)

                            groups['thta_outter'] = thta_outter
                            groups['points_thta_max'] = points_thta_max
                            groups['outterData'] = differItem;

                            group['Innerdata'] = innerItem
                            group['n_inner'] = n_inner
                            group['thta'] = thta;
                            group['r_inner'] = r_inner;
                            group['r_outter'] = r_outter;


                            differItem.forEach((item, idiffer) => {
                                let angle = points_thta_max + thta / 2 - thta_outter * (idiffer + 1)
                                item.x = _origin[0] + r_outter * Math.cos(-angle * 3.14 / 180)
                                item.y = _origin[1] + r_outter * Math.sin(-angle * 3.14 / 180)
                                item['ox'] = group.x;
                                item['oy'] = group.y;
                                _data.push(item)
                                _groups_update.push(item)

                                gg_nodes.push(item)
                            })



                        })
                        group._children = gg_nodes;
                    } else {
                        //内圈坐标
                        let n_inner = innerItem.length;
                        let r_inner = 30 * n_inner;
                        let thta = 360 / n_inner;


                        group['Innerdata'] = innerItem
                        group['n_inner'] = n_inner
                        group['thta'] = thta;
                        group['r_inner'] = r_inner;


                        let pointItem_inner = _this.getVertices(_origin, r_inner, n_inner);
                        innerItem.forEach((item, i) => {
                            item.x = pointItem_inner[i].x
                            item.y = pointItem_inner[i].y
                            _data.push(item)
                            _groups_update.push(item)

                            gg_nodes.push(item)

                        })
                        group._children = gg_nodes;
                    }

                } else if (group.type == 'EBGP') {
                    let BGP = [];
                    let bgp_group = [];
                    if (group.children && group.children.length > 0) {
                        group.children.forEach((child, i) => {
                            child.children.forEach((childSon, ichild) => {
                                BGP.push(childSon)
                            })
                        })
                    } else {
                        BGP.push(group)
                    }

                    let bgp_n = BGP.length;
                    let bgp_pointItem = _this.getVertices(_origin, bgp_n * 40, bgp_n);


                    BGP.forEach((item, i) => {
                        item.x = bgp_pointItem[i].x;
                        item.y = bgp_pointItem[i].y;
                        item['ox'] = group.x;
                        item['oy'] = group.y;
                        _data.push(item);
                        _groups_update.push(item)

                        bgp_group.push(item);
                    })
                    group["Innerdata"] = BGP
                    group["n_inner"] = bgp_n
                    group["r_inner"] = bgp_n * 40;

                    group._children = bgp_group;

                } else {
                    let other_group = [];
                    group.children.forEach((child, i) => {
                        child.x = pointItem[i].x;
                        child.y = pointItem[i].y;
                        child['ox'] = group.x;
                        child['oy'] = group.y;
                        _data.push(child);
                        _groups_update.push(child)
                        other_group.push(child);
                    })

                    group["Innerdata"] = other_group
                    group["n_inner"] = other_group.length
                    group["r_inner"] = other_group.length * 40;

                    group._children = other_group;

                }

            } else {
                _data.push(group);
            }
        })
        _this._data = _data;
        _this._groups_update = _groups_update
    }

    initNodeGroupPosition() {
        let _this = this;
        let data = _this.data

        //新建一个力导向图

        this.simulation = d3.forceSimulation(data)
            .force("charge", d3.forceManyBody().strength(-650).distanceMin(1))
            .force("collision", d3.forceCollide().radius(d => 400).strength(1).iterations(0))
            // 在 y轴 方向上施加一个力把整个图形压扁一点
            .force('yt', d3.forceY().strength(() => 0.025))
            .force('yb', d3.forceY(900).strength(() => 0.025))
            .force('center', d3.forceCenter(450, 250))

        this.group_nodes_data = [];
        this.single_nodes_data = [];

        data.forEach((item) => {
            if (item.children && item.children.length > 0) {
                _this.group_nodes_data.push(item)
               
            } else {
                _this.single_nodes_data.push(item)
            }
        })
        console.log(this.group_nodes_data)
        console.log(this.single_nodes_data)

    }

    //根据多边形获取定位点
    getVertices(origin, r, n) {
        if (typeof n !== 'number') return;
        var ox = origin[0];
        var oy = origin[1];
        var angle = 360 / n;
        var i = 0;
        var points = [];
        var tempAngle = 0;
        while (i < n) {
            tempAngle = (i * angle * Math.PI) / 180;
            points.push({
                x: ox + r * Math.sin(tempAngle),
                y: oy + r * Math.cos(tempAngle)
            });
            i++;
        }
        return points;
    }

    //获取多边形几何中心点
    getMulCenter(polygon) {
        d3.polygonCentroid(polygon)
    }

    //两点的中心点
    getCenter(x1, y1, x2, y2) {
        return [(x1 + x2) / 2, (y1 + y2) / 2]
    }

    //两点的距离
    getDistance(x1, y1, x2, y2) {
        return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
    }

    //两点角度
    getAngle(x1, y1, x2, y2) {
        var x = Math.abs(x1 - x2);
        var y = Math.abs(y1 - y2);
        var z = Math.sqrt(x * x + y * y);
        return Math.round((Math.asin(y / z) / Math.PI * 180));
    }

    //两点角度
    getAngle1(x1, y1, x2, y2) {
        var x = Math.abs(x1 - x2);
        var y = Math.abs(y1 - y2);
        var z = Math.sqrt(x * x + y * y);
        let x_c = x1 - x2
        let y_c = y1 - y2
        if (x_c == 0 && y_c > 0) {
            return 270
        }
        if (x_c == 0 && y_c < 0) {
            return 90
        }

        if (x_c > 0 && y_c == 0) {
            return 360
        }
        if (x_c < 0 && y_c == 0) {
            return 180
        }

        if (x_c > 0 && y_c > 0) {
            return 360 - Math.round((Math.asin(y / z) / Math.PI * 180))
        }

        if (x_c > 0 && y_c < 0) {
            return Math.round((Math.asin(y / z) / Math.PI * 180))
        }
        if (x_c < 0 && y_c < 0) {
            return 180 - Math.round((Math.asin(y / z) / Math.PI * 180))
        }

        if (x_c < 0 && y_c > 0) {
            return 180 + Math.round((Math.asin(y / z) / Math.PI * 180))
        }


    }


    //初始化缩放器
    initZoom() {
        let self = this;
        let zoom = d3.zoom()
            .scaleExtent([0.5, 3])
            .on('zoom', function () {
                self.onZoom(this)
            });
        this.svg.call(zoom)
    }

    //初始化图标
    initDefineSymbol() {
        let defs = this.container.append('svg:defs');

        //箭头
        const marker = defs
            .selectAll('marker')
            .data(this.edges)
            .enter()
            .append('svg:marker')
            .attr('id', (link, i) => 'marker-' + i)
            .attr('markerUnits', 'userSpaceOnUse')
            .attr('viewBox', '0 -5 10 10')
            .attr('refX', symbolSize / 2 + padding)
            .attr('refY', 0)
            .attr('markerWidth', 14)
            .attr('markerHeight', 14)
            .attr('orient', 'auto')
            .attr('stroke-width', 2)
            .append('svg:path')
            .attr('d', 'M2,0 L0,-3 L9,0 L0,3 M2,0 L0,-3')
            .attr('class', 'arrow')


        //数据库
        let database = defs.append('g')
            .attr('id', 'database')
            .attr('transform', 'scale(0.042)');

        database.append('path')
            .attr('d', 'M512 800c-247.42 0-448-71.63-448-160v160c0 88.37 200.58 160 448 160s448-71.63 448-160V640c0 88.37-200.58 160-448 160z')

        database.append('path')
            .attr('d', 'M512 608c-247.42 0-448-71.63-448-160v160c0 88.37 200.58 160 448 160s448-71.63 448-160V448c0 88.37-200.58 160-448 160z');

        database.append('path')
            .attr('d', 'M512 416c-247.42 0-448-71.63-448-160v160c0 88.37 200.58 160 448 160s448-71.63 448-160V256c0 88.37-200.58 160-448 160z');

        database.append('path')
            .attr('d', 'M64 224a448 160 0 1 0 896 0 448 160 0 1 0-896 0Z');

        //云
        let cloud = defs.append('g')
            .attr('id', 'cloud')
            .attr('transform', 'scale(0.042)')
            .append('path')
            .attr('d', 'M709.3 285.8C668.3 202.7 583 145.4 484 145.4c-132.6 0-241 102.8-250.4 233-97.5 27.8-168.5 113-168.5 213.8 0 118.9 98.8 216.6 223.4 223.4h418.9c138.7 0 251.3-118.8 251.3-265.3 0-141.2-110.3-256.2-249.4-264.5z')



    }

    //初始化链接线
    initLink() {
        this.drawLinkLine();
        this.drawLinkText();
    }

    updateGroupPosition(d) {
        d._children = [];
        let _origin = [d.x, d.y]
        let _this = this;

        let _groups_update = []
        if (d.type == 'OSPF') {
            let innerItem = d.Innerdata
            let n_inner = d.n_inner
            let thta = d.thta;
            let r_inner = d.r_inner;

            let pointItem_inner = _this.getVertices(_origin, r_inner, n_inner);

            innerItem.forEach((item, i) => {
                item.x = pointItem_inner[i].x
                item.y = pointItem_inner[i].y
                item['ox'] = d.x;
                item['oy'] = d.y;
                _groups_update.push(item)

                d._children.push(item)
            })


            let outterGroup = d.outterGroup

            if (outterGroup && outterGroup.length > 0) {


                let r_outter = d.r_outter;

                outterGroup.forEach((groups) => {
                    let points_thta_max = groups.points_thta_max
                    let thta_outter = groups.thta_outter
                    let differItem = groups.outterData;
                    differItem.forEach((item, idiffer) => {
                        let angle = points_thta_max + thta / 2 - thta_outter * (idiffer + 1)
                        item.x = _origin[0] + r_outter * Math.cos(-angle * 3.14 / 180)
                        item.y = _origin[1] + r_outter * Math.sin(-angle * 3.14 / 180)
                        item['ox'] = d.x;
                        item['oy'] = d.y;
                        d._children.push(item)
                        _groups_update.push(item)
                    })
                })
            }



        } else if (d.type == 'EBGP' || d.type == 'IBGP') {
            let innerItem = d.Innerdata
            let n_inner = d.n_inner
            let thta = d.thta;
            let r_inner = d.r_inner;

            let pointItem_inner = _this.getVertices(_origin, r_inner, n_inner);

            innerItem.forEach((item, i) => {
                item.x = pointItem_inner[i].x
                item.y = pointItem_inner[i].y
                item['ox'] = d.x;
                item['oy'] = d.y;
                _groups_update.push(item)

                d._children.push(item)
            })


        } else {

            _groups_update.push(d)
        }

        if (this._groups_update.length > 0) {
            this._groups_update.forEach((item) => {
                _groups_update.forEach((itemChild) => {
                    if (itemChild.id == item.id) {
                        item.x = itemChild.x;
                        item.y = itemChild.y;
                        item.ox = itemChild.ox;
                        item.oy = itemChild.oy;
                    }
                })
            })

        } else {
            this._groups_update = _groups_update;
        }

    }
    //初始化节点
    initNode() {
        var self = this;
        console.log(this.group_nodes_data)
        console.log(this.single_nodes_data)
        //节点容器
        this.nodes = this.container.selectAll(".node")
            .data(this.single_nodes_data)
            .enter()
            .append("g")
            .attr("transform", function (d) {
                return "translate(" + d.x + "," + d.y + ")";
            })
            .call(
                self.dragGroup(self.simulation)
            )
            // .call(d3.drag()
            //     .on("drag", function (d) {
            //         self.onDrag(this, d)
            //     })
            // )
            .on('click', function (d) {
                alert(`${d.id},---${d.x},${d.y}`)
            })

        //节点背景默认覆盖层
        this.nodes.append('circle')
            .attr('r', symbolSize / 2 + padding)
            .attr('class', 'node-bg');



        this.group_nodes = this.container.selectAll(".group_nodes")
            .data(self.group_nodes_data)
            .enter()
            .append("g")
            .classed("group_nodes", true)
            .call(
                self.dragGroup(self.simulation)
            )
            // .attr("transform", function (d) {
            //     return "translate(" + d.x + "," + d.y + ")";
            // })
            // .call(d3.drag()
            //     .on("drag", function (d) {
            //         self.onDrag(this, d)
            //     })
            // )
            // )
            //    .call(self.dragGroup(self.simulation))
            .on('click', function (d) {
                alert(`${d.id},---${d.x},${d.y}`)
            })

        this.group_nodes_circle = this.group_nodes.append("circle").attr('r', 30).attr('cx', d => d.x).attr('cy', d => d.y).attr('storke', 'red')
            .on('click', function (d) {
                alert(`${d.id},---${d.x},${d.y}`)
            })




        this.arrea_nodes = this.group_nodes.selectAll(".nodeChild").data(d =>
            d._children).enter()
            .append("g")
            // .attr('pointer-events','none')
            .classed('nodeChild', true)
            .call(d3.drag()
                .on("drag", function (d) {
                    self.onDrag(this, d)
                })
            )
            .on('click', function (d) {
                alert(`${d.id},---${d.x},${d.y}`)
            })



        //节点图标
        this.drawNodeSymbol(this.nodes);
        //节点标题
        this.drawNodeTitle(this.nodes);
        //节点其他说明
        this.drawNodeOther(this.nodes);
        this.drawNodeCode(this.nodes);


        //节点图标
        this.drawNodeSymbol(this.arrea_nodes);
        //节点标题
        this.drawNodeTitle(this.arrea_nodes);
        //节点其他说明
        this.drawNodeOther(this.arrea_nodes);
        this.drawNodeCode(this.arrea_nodes);

    }

    //画节点语言标识
    drawNodeCode(nodes) {
        this.nodeCodes = nodes.filter(item => item.type == 'app')
            .append('g')
            .attr('class', 'node-code')
            .attr('transform', 'translate(' + -symbolSize / 2 + ',' + symbolSize / 3 + ')')

        this.nodeCodes
            .append('circle')
            .attr('r', d => fontSize / 2 * d.code.length / 2 + 3)

        this.nodeCodes
            .append('text')
            .attr('dy', fontSize / 2)
            .text(item => item.code);

    }

    //画节点图标
    drawNodeSymbol(nodes) {
        //绘制节点
        nodes.filter(
            item => item.type == 'app')
            .append("circle")
            .attr("r", symbolSize / 2)
            .attr("fill", '#fff')
            .attr('class', function (d) {
                return 'health' + d.health;
            })
            .attr('stroke-width', '5px')


        nodes.filter(item => item.type == 'database')
            .append('use')
            .attr('xlink:href', '#database')
            .attr('x', function () {
                return -this.getBBox().width / 2
            })
            .attr('y', function () {
                return -this.getBBox().height / 2
            })

        nodes.filter(item => item.type == 'cloud')
            .append('use')
            .attr('xlink:href', '#cloud')
            .attr('x', function () {
                return -this.getBBox().width / 2
            })
            .attr('y', function () {
                return -this.getBBox().height / 2
            })
    }

    //画节点右侧信息
    drawNodeOther(nodes) {
        //如果是应用的时候
        this.nodeOthers = nodes.filter(item => item.type == 'app')
            .append("text")
            .attr("x", symbolSize / 2 + padding)
            .attr("y", -5)
            .attr('class', 'node-other')

        this.nodeOthers.append('tspan')
            .text(d => d.time + 'ms');

        this.nodeOthers.append('tspan')
            .text(d => d.rpm + 'rpm')
            .attr('x', symbolSize / 2 + padding)
            .attr('dy', '1em');

        this.nodeOthers.append('tspan')
            .text(d => d.epm + 'epm')
            .attr('x', symbolSize / 2 + padding)
            .attr('dy', '1em')
    }

    //画节点标题
    drawNodeTitle(nodes) {
        //节点标题
        nodes.append("text")
            .attr('class', 'node-title')
            .text(function (d) {
                return d.name;
            })
            .attr("dy", symbolSize)

        nodes.filter(item => item.type == 'app').append("text")
            .text(function (d) {
                return d.active + '/' + d.total;
            })
            .attr('dy', fontSize / 2)
            .attr('class', 'node-call')

    }


    //画节点链接线
    drawLinkLine(data_d) {
        let _this = this
        var viewColors = ["rgba(71, 218, 218, 0.2)", "rgba(241, 118, 218, 0.4)",
            "rgba(213, 228, 138, 0.4)", "rgba(186, 234, 171, 0.4)",
            "rgba(144, 211, 245, 0.4)", "rgba(70, 232, 175, 0.4)", "rgba(67, 243, 84, 0.4)",
            "rgba(234, 197, 137, 0.4)", "rgba(178, 236, 72, 0.4)", "red"];
        let data = this._data;
        //   let group = this._groups



        let group = this.group_nodes_data
        var line = d3.line()
            .curve(d3.curveCatmullRomClosed);


        // group.forEach((item) =>{

        //     if(item.type !== 'IBGP'){
        //         let obj = {
        //             children:item._children,
        //             type:item.type
        //         }
        //         item.children.push(obj)
        //     }
        // })

        //先画区域后画线

        if (this.areaGroup) {
            this.areaGroup_path
                .attr(
                    'd', link => {
                        if (link.children && link.children.length > 0) {
                            if (link.children.length > 1) {
                                return line(this.genLinkGroupPath(link))
                            }
                        }
                    });


        } else {
            this.areaGroup = this.container.append('g').selectAll('.group_area').data(group).enter().append('g')

            this.areaGroup_path = this.areaGroup.selectAll('.group')
                .data(d => {
                    if (d.type !== 'IBGP') {
                        let obj = {children:d._children, type:d.type}
                        d.children.push(obj)
                        return d.children
                    } else {
                        return [d]
                    }
                })
                .enter()
                .append('g')
                .append('path')
                .attr('class', 'group')
                .attr(
                    'd', link => {
                        if (link.children && link.children.length > 0) {
                            if (link.children.length > 1) {
                                return line(this.genLinkGroupPath(link, data_d))
                            }
                        }
                    }
                ).attr('fill', (d, i) => {
                    return viewColors[i]
                })
                .attr('stroke', (d, i) => {
                    return 'blue'
                })
                .attr('stroke-width', '1');


        }

        if (this.lineGroup) {
            this.lineGroup.selectAll('.link')
                .attr('x1', d => {
                    if(data[d.source].ox){
                        return  data[d.source].x + data[d.source].ox
                    } else{
                       return data[d.source].x
                    }
                }
                )
                .attr('y1', d => {
                    if(data[d.source].oy){
                        return  data[d.source].y +  + data[d.source].oy
                    } else{
                       return  data[d.source].y
                    }
                })
                .attr('x2', d => {
                    if(data[d.target].ox){
                        return  data[d.target].x + data[d.target].ox
                    } else{
                       return data[d.target].x
                    }
                })
                .attr('y2', d => {
                    if(data[d.target].oy){
                        return  data[d.target].y +  data[d.target].oy
                    } else{
                        return data[d.target].y
                    }
                })
        } else {
            this.lineGroup = this.container.append('g')
            this.lineGroup.selectAll('.link')
                .data(this.edges)
                .enter()
                .append('line')
                .attr('class', 'link')
                .attr(
                    'marker-end', (link, i) => 'url(#' + 'marker-' + i + ')'
                )
                .attr('x1', d =>
                    data[d.source].x)
                .attr('y1', d => data[d.source].y)
                .attr('x2', d => data[d.target].x)
                .attr('y2', d => data[d.target].y)
                // .attr(
                //     'd', link => this.genLinkPath(link), )
                .attr(
                    'id', (link, i) => 'link-' + i
                )
                .on('click', () => { alert() })
        }


    }

    genLinkGroupPath(d) {
        let _this = this
        let arr = [];
        let data = this._groups_update;

        if (d.children && d.children.length > 0) {
            d.children.forEach((childItem, i) => {
                data.forEach((item, index) => {
                    if (childItem.id === item.id) {

                        let obj = []
                        obj[0] = item.x;
                        obj[1] = item.y;
                        arr.push(obj);
                    }
                })

            })
        }

        if (arr.length > 2) {
            let OutData = d3.polygonHull(arr)
            return OutData
        } else if (arr.length == 2) {
            let k = (arr[1][0] - arr[0][0]) / (arr[0][1] - arr[1][1])
            let center = _this.getCenter(arr[0][0], arr[0][1], arr[1][0], arr[1][1])
            let b = center[1] - k * center[0]

            if (k && parseInt(k) !== 0) {
                let y1 = center[1] + 20
                let x1 = (y1 - b) / k
                let _arr1 = [x1, y1]
                arr.push(_arr1)

                let y2 = center[1] - 20
                let x2 = (y2 - b) / k
                let _arr2 = [x2, y2]
                arr.push(_arr2)
            } else {
                let y1 = center[1]
                let x1 = center[0] + 30
                let _arr1 = [x1, y1]
                arr.push(_arr1)

                let y2 = center[1]
                let x2 = center[0] - 30
                let _arr2 = [x2, y2]
                arr.push(_arr2)
            }


            let OutData = d3.polygonHull(arr)

            return OutData
        }
    }

    genLinkPath(d) {
        let data = this._data;
        let sx = data[d.source].x;
        let tx = data[d.target].x;
        let sy = data[d.source].y;
        let ty = data[d.target].y;
        return 'M' + sx + ',' + sy + ' L' + tx + ',' + ty;
    }

    drawLinkText() {
        let data = this._data;
        let self = this;
        if (this.lineTextGroup) {
            this.lineTexts
                .attr('transform', getTransform)

        } else {
            this.lineTextGroup = this.container.append('g')

            this.lineTexts = this.lineTextGroup
                .selectAll('.linetext')
                .data(this.edges)
                .enter()
                .append('text')
                .attr('dy', -2)
                .attr('transform', getTransform)
                .on('click', () => { alert() })

            this.lineTexts
                .append('tspan')
                .text((d, i) => this._data[d.source].lineTime + 'ms,' + this._data[d.source].lineRpm + 'rpm');

            this.lineTexts
                .append('tspan')
                .text((d, i) => this._data[d.source].lineProtocol)
                .attr('dy', '1em')
                .attr('dx', function () {
                    return -this.getBBox().width / 2
                })
        }

        function getTransform(link) {
            let s = data[link.source];
            let t = data[link.target];
            let p = self.getCenter(s.x + (s.ox || null), s.y + (s.oy|| null), t.x + (t.ox || null), t.y + (t.oy|| null));
            let angle = self.getAngle(s.x + (s.ox|| null), s.y + (s.oy|| null), t.x + (t.ox|| null), t.y + (t.oy|| null));
            if (s.x + s.ox > t.x + (t.ox|| null) && s.y + (s.oy|| null) < t.y + (t.oy|| null) || s.x + (s.ox|| null) < t.x + (t.ox|| null) && s.y + (s.oy|| null) > t.y + (t.oy|| null)) {
                angle = -angle
            }
            return 'translate(' + p[0] + ',' + p[1] + ') rotate(' + angle + ')'
        }
    }


    update(d) {
        this.drawLinkLine(d);
        this.drawLinkText(d);
    }

    //拖拽方法
    onDrag(ele, d) {
        d.x = d3.event.x;
        d.y = d3.event.y;
        d3.select(ele)
            .attr('transform', "translate(" + d3.event.x + "," + d3.event.y + ")")
        this.update(d);
    }

    //拖组
    dragGroup(simulation) {
        let _this = this;
        function dragstarted(d) {
            if (!d3.event.active) simulation.alphaTarget(1).restart();
            d.fx = d.x;
            d.fy = d.y;
        }

        function dragged(d) {
            d.fx = d3.event.x;
            d.fy = d3.event.y;
        }

        function dragended(d) {
            if (!d3.event.active) simulation.alphaTarget(0);
            simulation.stop()
            d.fx = null;
            d.fy = null;
        }

        //  _this.update()

        return d3.drag()
            .on("start", dragstarted)
            .on("drag", dragged)
            .on("end", dragended);
    }

    //缩放方法
    onZoom(ele) {
        var transform = d3.zoomTransform(ele);
        this.scale = transform.k;
        this.container.attr('transform', "translate(" + transform.x + "," + transform.y + ")scale(" + transform.k + ")")
    }

}